/*
 * Copyright 2010 - 2011, The PLDesktop Development Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include "output.h"

#define VIDEO                   0xB8000

PLOutput::PLOutput() : m_x(0), m_y(0), m_width(80), m_height(25), m_attr() {
}

void PLOutput::cls() {
	int i;
	int j;
	m_video = (unsigned char *) VIDEO;
	for (j = m_y ; j < m_height ; j++) {
		for (i = m_x ; i < m_width ; i++) {
			*(m_video + ((j * COLUMNS * 2) + i * 2)) = 0;
		}
	}
	m_xpos = 0;
	m_ypos = 0;
	cleared();
}

void PLOutput::printf(const char *format, ...) {
	char **arg = (char **)&format;
	int c;
	char buf[20];
	arg++;
	while((c = *format++) != 0) {
		if(c != '%') {
			putchar(c, m_attr);
		} else {
			char *p;
			c = *format++;
			switch (c) {
				case 'd':
				case 'u':
				case 'x':
					itoa(buf, c, *((int *)arg++));
					p = buf;
					printString(p);
					break;
				case 's':
					p = *arg++;
					if(! p) {
						p = (char *)"(null)";
					}
					printString(p);
					break;
				default:
					putchar(*((int *) arg++), m_attr);
					break;
			}
		}
	}
}

void PLOutput::newline() {
	m_xpos = 0;
	m_ypos++;
	if(m_ypos >= m_y + m_height) {
		m_ypos = 0;
	}
}

void PLOutput::printString(char *s) {
	while(*s) {
		putchar(*s++, m_attr);
	}
}

void PLOutput::itoa(char *buf, int base, int d) {
	char *p = buf;
	char *p1, *p2;
	unsigned long ud = d;
	int divisor = 10;
	/* If %d is specified and D is minus, put `-' in the head. */
	if (base == 'd' && d < 0) {
		*p++ = '-';
		buf++;
		ud = -d;
	} else if (base == 'x') {
		divisor = 16;
	}
	/* Divide UD by DIVISOR until UD == 0. */
	do {
		int remainder = ud % divisor;
		*p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
	} while (ud /= divisor);
	/* Terminate BUF. */
	*p = 0;
	/* Reverse BUF. */
	p1 = buf;
	p2 = p - 1;
	while (p1 < p2) {
		char tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2--;
	}
}

void PLOutput::moveX(int newX) {
	if(newX > m_x + m_width) {
		newX = m_x + m_width;
	}
	m_xpos = m_x + newX;
}

void PLOutput::moveY(int newY) {
	if(newY > m_y + m_height) {
		newY = m_height;
	}
	m_ypos = m_y + newY;
}
